#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

import os
import sys
import shlex
import logging
import argparse
import tempfile
import shutil
import glob
import subprocess
from multiprocessing import Process

HTTPS_PROXY_STR = "https_proxy"


class Task(Process):
    @staticmethod
    def log_init():
        logger = logging.getLogger()
        logger.setLevel(logging.INFO)
        loglevel = os.environ.get("LOG")
        if loglevel is not None:
            formatter = logging.Formatter(fmt='[{asctime} {levelname} {filename}:{lineno} {funcName:4}] {message}',
                                          style="{")
            if loglevel == "debug":
                logger.setLevel(logging.DEBUG)
            elif loglevel == "warn":
                logger.setLevel(logging.WARNING)
            elif loglevel == "error":
                logger.setLevel(logging.ERROR)
            else:
                logger.setLevel(logging.INFO)
        else:
            formatter = logging.Formatter(fmt='[{levelname}] {message}',
                                          style='{')
            handler = logging.StreamHandler(sys.stdout)
            handler.setFormatter(formatter)
            logger.handlers = []
            logger.addHandler(handler)

    @staticmethod
    def format_command(command, sudo=False):
        cmd_args: list[str] = []
        if isinstance(command, list):
            cmd_args = command
        elif isinstance(command, str):
            cmd_args = shlex.split(command)
            cmd_args[0] = shutil.which(cmd_args[0])
            if cmd_args[0] is None:
                raise Exception(f"{cmd_args}不存在，请检查命令或环境配置")
        else:
            raise Exception("Command with invalid instance")
        sudo_cmd = shutil.which("sudo")
        if sudo and sudo_cmd and cmd_args[0] != sudo_cmd:
            cmd_args.insert(0, sudo_cmd)
        return cmd_args
    
    def chdir(self, path):
        logging.info(f"chdir: {path}")
        os.chdir(path)

    def run_command(self, command, check=True, sudo=False, capture_output=False):
        logging.info(f">>>> {command}")
        command = self.format_command(command, sudo)
        return subprocess.run(command, check=check, timeout=600, capture_output=capture_output)


class WorkPrepare(Task):
    def __init__(self):
        super().__init__()
        parser = argparse.ArgumentParser(
            prog="openUBMC Development environment initialization",
            formatter_class=argparse.RawTextHelpFormatter
        )
        parser.add_argument("-path", "--bmc_sdk_path", help="bmcsdk压缩文件路径，该文件可从openUBMC社区的应用市场下载", required=True)
        parser.add_argument("-user", "--openubmc_user", help="openUBMC社区用户名", required=True)
        parser.add_argument("-psw", "--openubmc_password", help="openUBMC社区用户密码", required=True)
        parsed_args, _ = parser.parse_known_args(sys.argv)

        self.home = os.environ["HOME"]
        self.cwd = os.getcwd()
        self.bmc_sdk_path = parsed_args.bmc_sdk_path
        self.user = parsed_args.openubmc_user 
        self.password = parsed_args.openubmc_password 
        
    def proxy_check(self):
        https_proxy = os.environ.get(HTTPS_PROXY_STR)
        if https_proxy:
            logging.warning("检测到环境设置了https_proxy代理，可能导致初始化失败，请确认是否关闭代理运行？(Y/N)")
            if input().upper() == "Y":
                os.environ[HTTPS_PROXY_STR] = ""
                os.environ[HTTPS_PROXY_STR.upper()] = ""
    
    def environ_check(self):
        sudouser = os.environ.get("SUDO_USER")
        if sudouser is not None:
            raise Exception("请直接执行，不支持以sudo环境执行脚本")
        with open("/etc/issue", "r") as fq:
            issue = fq.readline().strip()
            if not issue.startswith("Ubuntu 24.04"):
                raise Exception(f"仅支持Ubuntu 24.04操作系统，当前系统为 {issue}")
    
    def ubuntu_init(self):
        self.run_command("ln -snf /bin/bash /bin/sh", sudo=True)
        logging.info("Initial ubuntu env")
        self.run_command(
            f"sed -i 's/archive.ubuntu/mirrors.huaweicloud/g' /etc/apt/sources.list.d/ubuntu.sources", 
            sudo=True, check=False
        )
        self.run_command(
            f"sed -i 's/security.ubuntu/mirrors.huaweicloud/g' /etc/apt/sources.list.d/ubuntu.sources", 
            sudo=True, check=False
        )
        self.run_command("apt-get update", sudo=True)
       
    def install_dependencies(self):
        self.run_command(
            f"apt-get install -y python3 python3-pip python3-dev git wget curl ca-certificates \
            ipmitool dbus-x11 libdbus-1-dev dbus \
            pkgconf libglib2.0-dev gcc-9 g++-9 unzip npm", 
            sudo=True
        )
        self.run_command(
            f"update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 20 \
            --slave /usr/bin/g++ g++ /usr/bin/g++-9 --slave /usr/bin/gcov gcov /usr/bin/gcov-9", 
            sudo=True
        )
        self.run_command(f"apt remove -y python3-urllib3 python3-distro", sudo=True)
        self.run_command(f"apt autoremove -y", sudo=True)

    def python_config(self):
        self.run_command(
            f"pip config set global.index-url https://mirrors.huaweicloud.com/repository/pypi", 
            sudo=True
        )
        self.run_command(
            f"pip config set global.extra-index-url https://mirrors.huaweicloud.com/repository/pypi/simple", 
            sudo=True
        )
        self.run_command(
            f"pip config set global.trusted-host 'mirrors.huaweicloud.com'", 
            sudo=True
        )

    def install_old_openssl(self):
        tmpdir = tempfile.TemporaryDirectory()
        self.chdir(tmpdir.name)
        self.run_command(
            f"wget https://mirrors.huaweicloud.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb"
        )
        self.run_command(f"dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb", sudo=True)
        os.chdir(self.cwd)

    def install_dev_tools(self):
        real_path = os.path.join(self.cwd, self.bmc_sdk_path)
        tmpdir = tempfile.TemporaryDirectory()
        self.chdir(tmpdir.name)
        self.run_command(f"unzip {real_path} ", sudo=True)
        self.run_command(f"cp -rf rtos_compiler {self.home}", sudo=True)
        self.run_command(f"cp -rf sdk {self.home}", sudo=True)
        self.run_command(f"cp -rf sdk/hi1711sdk.tar.gz {self.home}/rtos_compiler", sudo=True)
        self.run_command(f"cp -rf lua-format /usr/bin", sudo=True)
        self.run_command(f"chmod +x /usr/bin/lua-format", sudo=True)
        self.run_command(f"chmod -R +x hpm_tools", sudo=True)
        self.run_command(f"cp -rf hpm_tools/. /usr/local/bin", sudo=True)
        os.chdir(self.cwd)

    def install_node(self):
        self.run_command(f"npm install -g n", sudo=True)
        self.run_command(f"n 20.18.0")
        self.run_command(f"npm install -g npm@10.8.2", sudo=True)
 
    def install_bingo(self):
        tmpdir = tempfile.TemporaryDirectory()
        self.chdir(tmpdir.name)
        self.run_command(f"wget https://repo.openubmc.cn/25.03/tools/openUBMC-bingo_25.03.zip -O bingo.zip")
        self.run_command(f"unzip ./bingo.zip")
        whl_file = glob.glob(os.path.join(os.getcwd(), "*.whl"))[0]
        deb_file = glob.glob(os.path.join(os.getcwd(), "*.deb"))[0]
        if not whl_file or not deb_file:
            raise Exception(f"未找到bingo工具的安装包，无法进行安装")
        self.run_command(f"pip3 install {whl_file}  --break-system-packages", sudo=True)
        try:
            self.run_command(f"dpkg -i {deb_file}", sudo=True)
        except subprocess.CalledProcessError as e:
            self.run_command("apt install -y -f", sudo=True)
            self.run_command(f"dpkg -i {deb_file}", sudo=True)
        os.chdir(self.cwd)

    def install_studio(self):
        tmpdir = tempfile.TemporaryDirectory()
        self.chdir(tmpdir.name)
        try:
            self.run_command(f"wget https://repo.openubmc.cn/25.03/tools/BMC%20Studio.zip -O studio.zip")
        except Exception as e:
            raise e
        try:
            self.run_command(f"unzip ./studio.zip")
        except Exception as e:
            raise e
        deb_file = glob.glob(os.path.join(os.getcwd(), "*.deb"))[0]
        if not deb_file:
            raise Exception(f"未找到BMC Studio工具的安装包，无法进行安装")
        try:
            self.run_command(f"dpkg -i {deb_file}", sudo=True)
        except subprocess.CalledProcessError as e:
            self.run_command("apt install -y -f", sudo=True)
            self.run_command(f"dpkg -i {deb_file}", sudo=True)
        os.chdir(self.cwd)
    
    def install_cangjie(self):
        cangjie_file_name = "Cangjie-0.53.13-linux_x64.tar.gz"
        tmpdir = tempfile.TemporaryDirectory()
        self.chdir(tmpdir.name)
        try:
            self.run_command("wget https://cangjie-lang.cn/v1/files/auth/downLoad?nsId=142267&fileName" +
                         f"={cangjie_file_name}&objectKey=6719f1eb3af6947e3c6af327 -O {cangjie_file_name}")
        except Exception as e:
            raise e
        cangjie_file = glob.glob(os.path.join(os.getcwd(), "Cangjie-0.53.13-linux_x64.tar.gz"))[0]
        if not cangjie_file:
            raise Exception(f"找不到仓颉安装包")
        shutil.rmtree("/opt/cangjie", ignore_errors=True)
        try:
            self.run_command(f"rm -rf /opt/cangjie", sudo=True)
            self.run_command(f"tar -zxf ./{cangjie_file_name} -C /opt/", sudo=True)
        except Exception as e:
            raise e
        os.chdir(self.cwd)

    def conan_config(self):
        conan_cache = os.path.join(self.home, ".conan")
        self.run_command(f"rm -rf {conan_cache}", check=False, sudo=True)
        self.run_command("conan config init")
        self.run_command("conan config set general.revisions_enabled=1")
        self.run_command("conan remote add openubmc_dev 'https://conan.openubmc.cn/conan_1/' false -f")
        try:
            self.run_command(f"conan user {self.user} -p={self.password} -r openubmc_dev")
        except Exception as exc:
            logging.error("conan用户配置失败，请检查 -user 和 -psw 两个参数的值是否分别为openUBMC社区用户名和密码！")

    def install_sdk(self):
        os.chdir(self.cwd)
        self.run_command("bingo build -t install_sdk -b openUBMC -ucc")

    def install_qemu_compile_dependencies(self):
        self.run_command(
            f"apt-get install -y make bzip2 pkg-config libslirp-dev libpixman-1-dev ninja-build \
            libcap-ng-dev libfdt-dev libattr1-dev", sudo=True)
        
    def install_qemu_runtime_dependencies(self):
        self.run_command("cp /etc/apt/sources.list.d/ubuntu.sources \
                         /etc/apt/sources.list.d/ubuntu.sources.bak", sudo=True)
        self.run_command("sed -i 's/Suites:/Suites: plucky/g' /etc/apt/sources.list.d/ubuntu.sources", sudo=True)
        self.run_command("apt-get update", sudo=True)
        self.run_command("apt-get install -y libcapstone5", sudo=True)
        self.run_command("rm /etc/apt/sources.list.d/ubuntu.sources", sudo=True)
        self.run_command("mv /etc/apt/sources.list.d/ubuntu.sources.bak \
                         /etc/apt/sources.list.d/ubuntu.sources", sudo=True)
        self.run_command("apt-get update", sudo=True)

    def install_studio_runtime_dependencies(self):
        try:
            self.run_command("apt-get install -y wslu xdg-utils nginx", sudo=True)
        except Exception as e:
            raise e
        self.install_cangjie()

    def run(self):
        try:
            self.proxy_check()
            self.environ_check()
            self.ubuntu_init()
            self.install_dependencies()
            self.install_old_openssl()
            self.python_config()
            self.install_bingo()
            self.conan_config()
            self.install_dev_tools()
            self.install_node()
            self.install_sdk()
            # 初始化qemu编译和运行时依赖
            self.install_qemu_compile_dependencies()
            self.install_qemu_runtime_dependencies()
            logging.info("qemu依赖环境初始化成功")
            # 安装BMC Studio
            try:
                self.install_studio_runtime_dependencies()
                self.install_studio()
                logging.info("BMC Studio安装成功")
            except Exception as exc:
                logging.error(str(exc))
            logging.info("openUBMC开发者环境初始化完成！")
        except Exception as exc:
            if os.environ.get("LOG"):
                import traceback
                logging.error(traceback.format_exc())
            msg = str(exc)
            logging.error(msg)
            return -1
        return 0

if __name__ == "__main__":
    wk = WorkPrepare()
    sys.exit(wk.run())